#i should check stackexchange more often
Explore tagged Tumblr posts
isoddtosay ¡ 10 months ago
Text
Tumblr media
3 notes ¡ View notes
xieyouji-xiegushi ¡ 2 years ago
Text
Just What I Needed (Chapter 3)
Cross-posting my fics while AO3 is down! This is a multi-chapter fic; please check out the contents page for additional tags, overall CWs and other chapters before reading!
Title: Just What I Needed (Chapter 3)
Fandom: Supernatural
Rating: E
Ship: Destiel
Chapter 3 CWs: none
Summary: All Sam and Dean have to their names right now is $200, a '67 Chevy Impala, and a lead.
Dean dropped Sam off outside the library. Sam waved, wishing him a good date and reminding him to be careful. Dean was relaxed. He’d managed to wash his hair under a standpipe at the gas station earlier, and he had one of his last clean shirts on. He knew he didn’t exactly look his best, but at least Castiel probably wouldn’t be able to guess that he was effectively homeless.
He parked two blocks away from the Cheesecake Factory at precisely 6.45, giving him enough time to walk the rest of the way. He didn’t like to park right outside in case his jilted date tried to follow him. It wouldn’t do to have some angry guy memorising his plates. He walked briskly, not because he was cold, but actually a little excited. He tried to contain himself, but it was a long time since he’d been on anything that had even the semblance of a real date. He might have been out here scamming older guys for food, but they were out to get something for themselves too. He just didn’t usually give it to them.
Reminding himself that, no matter how pleasant the target, this was still just a scam, Dean hurried inside. Castiel was waiting just inside of the door. He smiled when he saw Dean.
“Aaron, I presume?”
“That’s me. Shall we grab a table?”
“Yes, we should.”
After they were situated, with two glasses of water and their food on the way, Castiel decided it was time to start the conversation.
“I hope this is okay. The restaurant, I mean. I never feel comfortable at expensive places.”
“Oh, no, it’s fine. I get that.” Dean did get it. He was all about quantity over quality, especially recently.
“Good,” Castiel responded, before falling silent. Dean waited for a couple of minutes, but there was no follow-up. Odd. Maybe Castiel was nervous. Okay, Dean could work with that.
“So, uh, do you come here often?”
Dean kicked himself internally. Why was that the thing that came out of his mouth? If he’d had a brain, he’d be dangerous.
“No, I do not frequent the Cheesecake Factory. I mainly eat at home,” Castiel answered the question, apparently taking it at face value. He looked down at his drink. More silence. Dean began to feel a bit awkward. The conversation just wasn’t flowing the way it had seemed to earlier. It was… weird.
“Hey, uh, are you okay?” he asked.
“Yes. Sorry. My people skills are… rusty. I mainly talk to computers. I haven’t been on a proper date since… well, I can’t remember, actually. I’ve forgotten what to do.”
Dean laughed gently. That made two of them.
“Well, you were pretty conversational earlier. Just stick with that.”
“Oh. That. Texting is easier than face to face interactions. And the questions thing – I, uh, saw that on stackexchange. I’m nowhere near that smooth in real life.”
Well, that made sense. Dean felt just the smallest twinge of disappointment, but he shelved it. If the date was bad, he wouldn’t feel guilty for cutting out early.
“I think, this is the part where I ask you to tell me about yourself, is it not?” Castiel continued. “How long have you been in town?”
“Just a few days. You’re local?”
“Yep, born and bred. You here for long?”
“Not sure yet. Probably not. We move around a lot.”
“We?”
Damn. Dean usually went out of his way to avoid giving any personal information to his dates. Castiel was more observant than he was used to. Most of the guys he went out with just wanted to talk about themselves. Oh well, he supposed he could give a few details, as long as they weren’t identifying.
“Yeah, I’m with my family. My Dad, and my kid brother.”
“Your dad? How old did you say you were again?”
“I didn’t, but I’m 24.” Dean lied. Really, he was 20, but a lot of guys were put off by that, and the ones that weren’t tended to be trouble. “Family business. I help out and take care of Sammy.”
“That sounds pleasant. I haven’t seen my brothers for a long time. They’re not… the best people.”
Oh. Okay. Awkward, and a little oversharing. Castiel wasn’t really what Dean had expected, but, somehow, he found that he didn’t mind. It was honestly just nice to meet someone who liked to listen as much as talk.
“Sorry to hear that, man. Having a brother… it’s awesome. Sammy’s the greatest kid. Does good in school, everyone likes him, you know. Never gets in trouble. Give him some apple pie and he’s happy as Larry.”
Dean lit up when he was talking about Sam, and Castiel noticed, smiling at him softly. It was a kind smile. It made Dean feel warm. Not many people looked at him like that these days.
“What’s the family business?”
“Oh, you know. Contracting. Short jobs, different cities, that sort of thing. We mostly live on the road.”
“Sounds interesting. Tiring, I imagine, but it must feel… freeing.” If Castiel had noticed how Dean had deflected the question, he didn’t comment. “I’m chained to a desk most days, I’m afraid. Not a very exciting life.”
“Well, thank god you met me,” Dean quipped, before his curiosity got the better of him. “Actually, if this is your first date in a while… why did you ask me out?”
“I don’t know. I hadn’t even opened Grindr in, oh, must’ve been months. Today I just decided to check it out, see what’s out there, and there you were, right at the top. I didn’t know you’d just come into town. But it seems, I don’t know, serendipitous.”
As he said this, Castiel met Dean’s eyes, and held his gaze for the longest they had managed so far. Dean could tell that he was completely sincere. He almost found himself agreeing. Castiel’s eyes were truly striking. Dean felt like he was at risk of answering any question Castiel asked as long as he was looking into his eyes.
Their food arrived, and Castiel got to work on his quickly, with Dean taking it considerably slower. The conversation was moving more naturally now. They talked about Castiel’s job, which sounded just as boring as he claimed it was, their hobbies (Dean left several off the list), music, and a bit more about their families. Dean was careful not to give anything else away. Castiel didn’t go into much detail about his, either. What he did say made it sound pretty complicated. Dean could relate. Neither of them pried beyond what they were willing to share.
Dean almost jumped out of his chair when he felt his phone ring. He quickly checked his watch – how was it 8.30 already? He hadn’t been looking at the time at all. He supposed he had just been enjoying Castiel’s company.
“Sorry, I gotta take this.”
“No problem.”
Dean walked away from the table and answered the phone.
“Hi, Sammy.”
“Ready to go?”
Dean hesitated, glancing back at Castiel, who was still sitting at the table. God, he was good-looking. A tiny part of him wanted to stay.
“Dean? Come on, I’m hungry.”
“Right, right. Sorry. I’ll be right there.”
He hung up and returned to the table. No need for a fake frown; he actually felt bad about leaving. Castiel clearly didn’t go out much. Dean felt like he was wasting a rare opportunity for him.
“Castiel, I’m so sorry. I have to go. My Dad has to go to work, so I gotta go home and take care of Sammy. Sorry, I was supposed to have the night free.”
Castiel was silent for a few seconds, before turning his face towards Dean with an understanding expression.
“It’s okay. Here, let’s get your food packed up.” He motioned for a waiter to come to the table. “Could we get this food to go? And add an apple pie to that, and the bill, please.”
“Apple pie?”
“Sammy’s favourite, right?”
Dean was taken aback. Now he felt really guilty.
“Hey, Aaron, I had a great time tonight. Could I get your number?”
“What? Oh, right, of course.”
Dean had been asked this after a date before of course. This time, though, he gave Castiel his real number. He felt his phone buzz in his pocket as Castiel drop-called him.
“There, now you’ve got mine. Ah, and just in time,” he said, as the waiter returned with the food. He handed the bags to Dean, who accepted them gratefully. “Text me when you get home, okay?”
“Uh, sure. Thanks, Castiel. Be seeing you.”
“I hope so.”
Dean turned and half-ran out of the restaurant. Castiel would hopefully assume it was because he was rushing home, but really Dean just didn’t know how to respond. When he got back to the car, he pulled out his phone and saved Castiel’s number, grinning stupidly. Yeah, he was totally smitten.
He got back to the library at 8.55. Sam was waiting.
“You’re late.”
“Five minutes! And I got you pie.”
“What? How did you manage that?”
“The guy. He ordered it.”
Sam gave him a sidelong look. “And? How was it?”
“It was nice. He was nice.”
“That’s good. Shame you’re not gonna see him again.”
Dean felt a slight pang of sadness. “Right. Yeah. I’m not into second dates, anyway.”
There was a faint buzzing sound, which Dean realised had come from his phone. He opened it to check the notification. Grindr. He opened it, just to see what it was.
hi
u into older
?
________________
Well, it was a bit soon after his last date, but maybe Dean could book in dinner for later in the week. It would give him one less thing to worry about.
i’m open
________________
Good start. Not shutting it down, but not looking like he was into it either. Dean had discovered that if he came on too strong, they didn’t feel as inclined to spend money on him.
u avail?
[location]
here
now
________________
Yikes.
buy a guy dinner first?
i’m free tomorrow
________________
no dinner
1 hr
p2p
200
u come or not?
________________
Dean wracked his brain. What was ‘p2p’, again? Drugs? No, drugs was ‘pnp’, or sometimes ‘pArty’. No, ‘p2p’ was… oh, right. Pay to play. 200. That must’ve meant $200. Damn.
Dean was under no illusion exactly what he would be doing for that $200. To be honest, he’d considered it before, sometime after they got down to their last $500. He just hadn’t really known how to actually, you know, find a job.
pics?
________________
[image]
[image]
[image]
________________
Well, one out of those three was not exclusively a dick pic. The guy was definitely older than Dean, but still only looked to be about early 50s. He wasn’t stunningly attractive or anything, but not bad. Dean made up his mind.
ok
just got off work
can I shower at your place?
________________
sure
________________
be right there
________________
Dean looked over at Sam, who was working on his food.
“Hey, Sammy. I’ve gotta go, uh, take care of something. I’m gonna bring the car, so you just lock yourself in, alright? It won’t take long.”
“Where are you going? Hunting? Can I come?”
“No, and no. It’s just… a thing. Don’t worry about it. I’ll be back before you know it.”
“Okay, sure. Just be careful, alright?”
“Yeah, yeah. Of course.”
Dean sped across town and parked two streets away from the location. He grabbed his phone, leaving the car keys with Sam. He reached the house and rang the doorbell, hopping nervously from one foot to the other. The man opened the door and looked him up and down.
“Hi. Come in.”
“Thanks.” Dean ducked inside, heading straight to the bathroom. In his haste, he missed the text that came through to his phone.
Hey, Aaron. Did you make it home okay?
- Castiel: 21.20
0 notes
mathdevelopment ¡ 7 years ago
Text
Player movement
This is one entry in a multi-part series. If you haven't read the start of the sandbox demo series, start reading here.
The time has finally come to let the player move around. There are a few ways to handle movement in a 2D game, depending on the type of game. If I were making a precision platformer, I would probably just want fixed speed movement, but I’m not so I’ll go for acceleration with a maximum speed.
Even with that approach there are multiple options though. Here's an equation I've used in the past:
\[v\left(t\right)=a+fv\left(t-1\right)\]
//This is what it would look like in code: player.Velocity *= f; // 0 < f < 1 player.Velocity += a;
\(a\) is the acceleration of the player or entity and \(f\) is the "decay" or friction, generally set to a high decimal value like 0.8. The maximum velocity in this approach is equal to \(\frac{a}{1-f}\). I'm sure you could prove that with limits or something, but I'm going to take the "if it seems to work it's probably right" approach. If I let \(a=1\), the formula evaluates to:
\[v\left(t\right)=s\left(1-f\right)+fv\left(t-1\right)\]
where \(f\) represents the accleration and \(s=v_{\max}\). Oh, and if we're going for low-level optimization, I can cut out a multiplication operation with this simplification:
\[v\left(t\right)=s+f\left(v\left(t-1\right)-s\right)\]
Mathematically, this formula works. In practice, the code is going to have more trouble with it. \(t\) is supposed to represent time, but computers don't always have the same time gap between frames. If I were to lock the framerate I could ignore that issue, but nobody likes framerate locks. To fix this, I'll move outside of algebra and into programming math. Oh, and let's change \(s\) to \(m\) and \(f\) to \(a\) while we're at it.
\[v\rightarrow m+a\Delta t\left(v-m\right)\]
\(\Delta t\) can really be in any time format I want, as long as I set \(a\) accordingly.
So let's put this into code! I'll start with horizontal movement first, as that doesn't really require that I actually implement physics.
if (keyboardState.IsKeyDown(Keybinds.Left)) targetSpeed -= 10; if (keyboardState.IsKeyDown(Keybinds.Right)) targetSpeed += 10; player.Velocity = new Vector2(targetSpeed + (0.9f * (float)gameTime.ElapsedGameTime.TotalSeconds * (player.Velocity.X - targetSpeed)), player.Velocity.Y); player.Position += player.Velocity.ToPoint();
But that didn't work. I mean, it worked in terms of the scaling (my math was right!) but the actual speeds and positions that things were at were wrong. After some testing (some of which involved an actual stopwatch) I realized the problem. I had multiplied the acceleration by the time step, but not the velocity when moving the player. But after I did that, the player wouldn't move at all. I immediately realized the issue: the distance moved per time step is less than one. The positions of entities are stored as points (for reasons that will be explained later), and points use integer x and y values, rather than Vector2s which consist of floating point numbers. I wanted to preserve the exact-ness of the position but still allow for decimal positions, so I decided to comprimise with this little bit of code:
public Vector2 Velocity { get; set; } public Point PointPosition { get { return Position.ToPoint(); } }
C# properties are beautiful, aren't they. I may regret this change later on, but I'll deal with it then. For now, I have other issues. Almost everything is working properly at this point, but the acceleration isn't visible. I changed \(a\) to 0.999f, but even that still wasn't noticable. The time step was too small for my large \(a\) values. At this point I also realized another problem. In the case in which a time step takes longer than one second (which should never happen in theory), everything will break. I'm sure speedrunners would love that, but I'm not making this for speedrunners. I need to guarantee that my \(a\) term is always less than one. I also need to guarantee that my \(a\) term is properly distributed over a second no matter how many updates are contained within that second.
I thought about this puzzle for a while until I finally came to my conclusion: If this is possible to solve, I don't know how to do it. If you can think of a solution to this, tweet me or ask me the answer, because I seriously have no idea. For now, I'm just going to remove the time step factor from the acceleration. Goodbye delta t, you will be missed.
\[v\rightarrow m+a\left(v-m\right)\]
For testing purposes, I'm going to make the player speed be 24 tiles/s or 1.5 chunks/s.
Of course though, the player's velocity shouldn't change mid-air, should it? Or if it does, it should change MUCH slower. My formula doesn't easily allow for things like air control, so while I could probably implement it by changing the \(a\) term while the player isn't grounded, I'll just add a "is player grounded" check before trying to change their velocity. Note that I haven't actually implemented any code that tells me if the player is grounded. I'm just using placeholder variables for now.
Now that I'm done with horizontal velocity (yes, all of that was just for horizontal velocity), I'm going to move on to vertical stuff. I might be able to just use straight acceleration, but I don't really want the player to be clipping through the ground. There are "ray"cast solutions to that, but I'm just going to assume that the player won't be going at ground clipping speeds for now. Is that ignorant? Yes. Do I care? Yes, but I'm willing to overlook it for now.
So I'm going to use raw acceleration anyways, even though I said it was a bad idea. Otherwise it's gonna feel like the player is hanging on to a bunch of balloons whenever move. How does 1 chunk/s2 sound for acceleration due to gravity? I think it sounds fine, so I'm gonna use that.
Let's go back to the collision from last time, specifically this line:
anyCollide = true;
Instead of just checking if there are any collisions, I'm also going to eject the player from the tile. This essentially means that if a player is inside of a tile, I'm going to move them just enough outside of the tile that they are resting right beside the tile. This is where my concern about using Position and PointPosition came from. When using floats for physics, there is often an issue of vertical jitter where the player is displaced just out of the tile, falls back into the tile the next frame, and then is displaced outside in the next frame. Hopefully that won't happen here, but I should keep in mind the possibility that it could.
But how will I perform ejection in the first place? It's not actually quite as hard as it sounds. Remember that stackoverflow answer that was actually a gamedev stackexchange answer that I linked in the previous post? That specifically mentions vertical ejection, but I'll apply the same idea for both axes. However, I won't eject on both axes. If I did, stuff like this would happen all the time:
Tumblr media
Where what I really want is this:
Tumblr media
To fix that, I'll look for the axis which has the lowest intersection, and eject on that axis. I'll know which direction by checking which side of the original entity center the intersection is on.
if (currentRect.Intersects(tileRect)) { anyCollide = true; Rectangle intersection = Rectangle.Intersect(currentRect, tileRect); if (intersection.Width < intersection.Height) { if (intersection.Center.X > currentRect.Center.X) { e.Position += -Vector2.UnitX * intersection.Width; } else { e.Position += Vector2.UnitX * intersection.Width; } e.Velocity *= Vector2.UnitY; } else { if (intersection.Center.Y > currentRect.Center.Y) { e.Position += -Vector2.UnitY * intersection.Height; } else { e.Position += Vector2.UnitY * intersection.Height; } e.Velocity *= Vector2.UnitX; } }
Tumblr media
It works! My problem now is that I have no jump. Adding a jump is easy, but making it only work while the player is grounded is trickier. You might not have noticed the flashing the the gif above due to the framerate of the gif, but the character was flashing between red and green every frame. This is actually a side effect of the jitter I mentioned earlier. The frame after the player is ejected from the ground, they're no longer intersecting the ground, and so they appear red again.
However, this is actually sort of weird behavior due to the semantics of how I programmed and arranged my code. By best guess has to do with the time step being so quick that -16 * UNIT_SIZE * gameTime.ElapsedGameTime.TotalSeconds, the delta-v on the y axis, is less than one.
After some quick testing, I discovered that my hypothesis was in fact incorrect. However, though I may have been wrong, I was certainly on the right track. Each frame, the position is not changed by the velocity, but by the velocity times the time step. Therefore, it would actually take four or five frames to accumulate enough delta-y to intersect the player again.
Creating a fix to this issue which is ignorant of the framerate is pretty tricky. One option is to do an additional intersection check with a rectangle expanded by one unit in every direction. Hopefully this new check can actually replace the old one, as if there is a collision with no intersection, the intersection width or height would be zero, as per the documentation.
I should be able to say that an entity is grounded if the collision pushes them up, or the height of an intersection is zero. It works... I think.
After a bit of testing I decided to increase the acceleration due to gravity, and everything seems to be working fi- oh wait, no, that's not right. I have accidentally implemented wall jumps. Let's fix this by checking the ejection direction of the expanded collision rectangle, and performing the old collision that we know worked.
And it works! The last change that I'm going to make for the post is to change the current lack of air control into a slower acceleration air control. I can do this by just cranking up the \(a\) value from earlier really high while the player isn't grounded.
Tumblr media
// These code blocks are getting way too long. bool anyCollide = false; e.Grounded = false; Rectangle entityRect = e.GetCollisionRect(); for (int x = entityRect.Left; x < entityRect.Right + Game1.UNIT_SIZE; x += Game1.UNIT_SIZE) { for (int y = entityRect.Top; y < entityRect.Bottom + Game1.UNIT_SIZE; y += Game1.UNIT_SIZE) { Tile t = GetTile(new Point(x.FloorDivide(Game1.UNIT_SIZE), y.FloorDivide(Game1.UNIT_SIZE))); if (t != null && t.HasCollision) { Rectangle currentRect = e.GetCollisionRect(); Rectangle expandedRect = currentRect.InflateThrough(1, 1); // Uses extension function of Rectangle.Inflate to make a clean one-liner. Rectangle tileRect = new Rectangle(x.FloorDivide(Game1.UNIT_SIZE) * Game1.UNIT_SIZE, y.FloorDivide(Game1.UNIT_SIZE) * Game1.UNIT_SIZE, Game1.UNIT_SIZE, Game1.UNIT_SIZE); if (expandedRect.Intersects(tileRect)) { Rectangle expandedIntersect = Rectangle.Intersect(expandedRect, tileRect); if (expandedIntersect.Height < expandedIntersect.Width && expandedIntersect.Center.Y > expandedRect.Center.Y) e.Grounded = true; anyCollide = true; if (currentRect.Intersects(tileRect)) { Rectangle intersection = Rectangle.Intersect(currentRect, tileRect); if (intersection.Width < intersection.Height) { if (intersection.Center.X > currentRect.Center.X) { e.Position += -Vector2.UnitX * intersection.Width; } else { e.Position += Vector2.UnitX * intersection.Width; } e.Velocity *= Vector2.UnitY; } else { if (intersection.Center.Y > currentRect.Center.Y) { e.Position += -Vector2.UnitY * intersection.Height; } else { e.Position += Vector2.UnitY * intersection.Height; } e.Velocity *= Vector2.UnitX; } } } } } }
And in honor of another game created using XNA, here are some vertical hoiks.
Tumblr media
They're a bit harder to control.
0 notes